/* 
 * File:   cameraInputeGeneratorTest.cpp
 * Author: picci
 *
 * Created on Oct 16, 2010, 3:41:01 PM
 */

#define BOOST_TEST_MODULE generators test
#include <boost/test/included/unit_test.hpp>

#include <cv.h>
#include <highgui.h>

#include "prj_definitions.h"
#include "generators/cameraInputGenerator.h"
#include "pipeline/pipeline_io.h"
#include "common/utility_data_structures.h"
#include "generators/genericGenerator.h"
#include "generators/bridgeGenerator.h"
#include "generators/resource/CvImgDirectoryGenerator.h"

struct camera_generators_fixture{
    camera_generators_fixture(){
        cig = 0; copy_cig = 0; assigned_cig = 0;
        skip_test = false;

        cig = new NAMESPACE::CameraInputGenerator();
        cig->set_key("Generators test", "CameraInputGeneratorTest");
    }

    ~camera_generators_fixture(){
        if(cig) delete cig;
        if(copy_cig) delete copy_cig;
        if(assigned_cig) delete assigned_cig;
    }

    NAMESPACE::CameraInputGenerator *cig, *copy_cig, *assigned_cig, *assigned_cig2;
    bool skip_test;
};

BOOST_AUTO_TEST_SUITE(generators_test)


BOOST_FIXTURE_TEST_SUITE(CameraInputGenerator_test, camera_generators_fixture)

BOOST_AUTO_TEST_CASE(CameraInputGenerator_generation_test){
    NAMESPACE::IOElement* generated;
    cv::Mat* frame;

    cig->open();
    BOOST_CHECK( cig->is_opened() );

    for(int i = 0; i < 100; i++){
        generated = cig->generate();
        frame = boost::any_cast<cv::Mat*>( generated->getElement() );
        BOOST_CHECK(frame);
        BOOST_CHECK(frame->size().height);
        BOOST_CHECK(frame->size().width);

        BOOST_CHECK(generated->getIOKey() == cig->get_key());
    }

    cig->close();
    BOOST_CHECK( !cig->is_opened() );
}

BOOST_AUTO_TEST_CASE(CameraInputGenerator_constructors_test){
    cig->open();
    NAMESPACE::IOElement* generated;
    cv::Mat* frame;

    for(int i = 0; i < 100; i++){
        generated = cig->generate();
        frame = boost::any_cast<cv::Mat*>( generated->getElement() );
        BOOST_CHECK(frame);
        BOOST_CHECK(frame->size().height);
        BOOST_CHECK(frame->size().width);
    }

    copy_cig = new NAMESPACE::CameraInputGenerator(*cig);

    assigned_cig = new NAMESPACE::CameraInputGenerator();
    NAMESPACE::CameraInputGenerator assigned_cig2;
    /* Double assignement is used to test if operator= correctly returns the self
     * reference
     */
    assigned_cig2 = *assigned_cig = *cig;
    
    BOOST_CHECK( *cig == *copy_cig );
    BOOST_CHECK( *cig == *assigned_cig );
    BOOST_CHECK( *cig == assigned_cig2 );

    BOOST_CHECK( cig->is_opened() );
    BOOST_CHECK( !copy_cig->is_opened() );
    BOOST_CHECK( !assigned_cig->is_opened() );

    // assigned_cig2 is a copy of cig. What if cig is assigned with a copy of itself?
    // Memory will be correctly deallocated? Let's test this
    *cig = assigned_cig2;

    cig->close();
}

BOOST_AUTO_TEST_SUITE_END()


BOOST_AUTO_TEST_SUITE(GenericGenerator_test)

BOOST_AUTO_TEST_CASE(GenericGenerator_generation_test){
    NAMESPACE::Generator* g = new NAMESPACE::GenericGenerator<cv::Mat>();
    g->set_key("Generators test", "GenericGeneratorTest");

    NAMESPACE::IOElement* generated;
    cv::Mat* frame;

    for(int i = 0; i < 100; i++){
        generated = g->generate();
        frame = 0;
        frame = boost::any_cast<cv::Mat*>( generated->getElement() );

        BOOST_CHECK(frame);
        BOOST_CHECK(generated->getIOKey() == g->get_key());
    }
    delete g;
}

BOOST_AUTO_TEST_CASE(GenericGenerator_constructors_test){
    NAMESPACE::GenericGenerator<std::string>* gg = new NAMESPACE::GenericGenerator<std::string>();
    gg->set_key("Generators test", "GenericGeneratorTest");
    NAMESPACE::IOElement* generated;
    std::string* s;

    for(int i = 0; i < 10; i++){
        generated = gg->generate();
        s = 0;
        s = boost::any_cast<std::string*>( generated->getElement() );
        BOOST_CHECK(s);
    }

    NAMESPACE::Generator* copy_gg = new NAMESPACE::GenericGenerator<std::string>(*gg);

    NAMESPACE::GenericGenerator<std::string>* assigned_gg = new NAMESPACE::GenericGenerator<std::string>();
    NAMESPACE::GenericGenerator<std::string> assigned_gg2;

    *assigned_gg = *gg;

    BOOST_CHECK( *gg == *copy_gg );
    BOOST_CHECK( *gg == *assigned_gg );

    assigned_gg2 = *gg;
    // assigned_gg2 is a copy of gg. What if cig is assigned with a copy of itself?
    // Memory will be correctly deallocated? Let's test this
    *gg = assigned_gg2;

    delete gg;
    delete copy_gg;
    delete assigned_gg;
}

BOOST_AUTO_TEST_SUITE_END()


BOOST_AUTO_TEST_SUITE(BridgeGenerator_test)

BOOST_AUTO_TEST_CASE(BridgeGenerator_generation_test){
    NAMESPACE::GenericGenerator<cv::Mat>* gg = new NAMESPACE::GenericGenerator<cv::Mat>();
    gg->set_key("Generators test", "BridgeGeneratorTest - generic generator");

    NAMESPACE::IOKey k;
    k.set_key("Generators test", "BridgeGeneratorTest");
    k.setType(typeid(cv::Mat*));
    NAMESPACE::Generator* bg = new NAMESPACE::BridgeGenerator(*gg, k);

    NAMESPACE::IOElement* generated;
    cv::Mat *frame, *bridge_frame;

    for(int i = 0; i < 10; i++){
        gg->generate();

        generated = bg->generate();
        bridge_frame = boost::any_cast<cv::Mat*>(generated->getElement());

        frame = boost::any_cast<cv::Mat*>(gg->last_generated()->getElement());
        BOOST_CHECK(bridge_frame == frame);
        BOOST_CHECK(generated->getIOKey() == k);
    }

    delete gg;
    delete bg;
}

BOOST_AUTO_TEST_SUITE_END()


BOOST_AUTO_TEST_SUITE(CvImgDirectoryGenerator_test)

BOOST_AUTO_TEST_CASE(CvImgDirectoryGenerator_generation_test){
    std::string path = "tests/directoryGenerators_test_folder";
    std::string img_a_filename = path + "/img_a.jpg";

    cv::Mat img_a = cv::imread(img_a_filename, -1);

    std::vector<cv::Mat*> check_img;
    check_img.push_back(&img_a);

    NAMESPACE::CvImgDirectoryGenerator* g = new NAMESPACE::CvImgDirectoryGenerator(path);
    g->set_key("Generators test", "CvImgDirectoryGenerator");

    NAMESPACE::IOElement* generated;
    std::vector<cv::Mat*> generated_img;

    NAMESPACE::IOKey k;
    k.set_key("Generators test", "CvImgDirectoryGenerator");
    k.setType(typeid(cv::Mat*));
    int i = 0;
    g->open();
    cv::Mat* tmp_m;
    while(generated_img.size() == 0 || g->is_opened()){
        generated = g->generate();
        tmp_m = boost::any_cast<cv::Mat*>(generated->getElement());
        if(tmp_m->data != NULL){
            generated_img.push_back(tmp_m);
        }

        BOOST_CHECK(generated->getIOKey() == k);
    }

    BOOST_CHECK(generated_img.size() == check_img.size());
    for(int j = 0; j < generated_img.size(); j++){
        uchar* gen_it = generated_img[j]->datastart;
        uchar* chk_it = check_img[j]->datastart;
        for(; gen_it != generated_img[j]->dataend; gen_it++, chk_it++)
            BOOST_CHECK(*gen_it == *chk_it);
    }

    g->close();
    delete g;
}

BOOST_AUTO_TEST_CASE(CvImgDirectoryGenerator_invalid_folder_test){
    std::string path = "tests/blablablablabla";
    NAMESPACE::CvImgDirectoryGenerator* g = new NAMESPACE::CvImgDirectoryGenerator(path);
    g->set_key("Generators test", "CvImgDirectoryGenerator");
    
    BOOST_CHECK_THROW(g->open(), NAMESPACE::AbstractResourceGenerator::bad_resource);

    delete g;
}

BOOST_AUTO_TEST_SUITE_END()
        

BOOST_AUTO_TEST_SUITE_END()